{
 "cells": [
  {
   "cell_type": "markdown",
   "id": "d51b6476",
   "metadata": {},
   "source": [
    "# MetaGPT快速尝鲜\n",
    "\n",
    "## **智能体**\n",
    "\n",
    "在MetaGPT看来，可以将智能体想象成环境中的数字人，其中\n",
    "\n",
    "智能体 = 大语言模型（LLM） + 观察 + 思考 + 行动 + 记忆\n",
    "\n",
    "这个公式概括了智能体的功能本质。为了理解每个组成部分，让我们将其与人类进行类比：\n",
    "\n",
    "1. **大语言模型（LLM）**：LLM作为智能体的\"大脑\"部分，使其能够处理信息，从交互中学习，做出决策并执行行动。\n",
    "2. **观察**：这是智能体的感知机制，使其能够感知其环境。智能体可能会接收来自另一个智能体的文本消息、来自监视摄像头的视觉数据或来自客户服务录音的音频等一系列信号。这些观察构成了所有后续行动的基础。\n",
    "3. **思考**：思考过程涉及分析观察结果和记忆内容并考虑可能的行动。这是智能体内部的决策过程，其可能由LLM进行驱动。\n",
    "4. **行动**：这些是智能体对其思考和观察的显式响应。行动可以是利用LLM生成代码，或是手动预定义的操作，如阅读本地文件。此外，智能体还可以执行使用工具的操作，包括在互联网上搜索天气，使用计算器进行数学计算等。\n",
    "5. **记忆**：智能体的记忆存储过去的经验。这对学习至关重要，因为它允许智能体参考先前的结果并据此调整未来的行动。\n",
    "\n",
    "## **多智能体**\n",
    "\n",
    "多智能体系统可以视为一个智能体社会，其中\n",
    "\n",
    "多智能体 = 智能体 + 环境 + 标准流程（SOP） + 通信 + 经济\n",
    "\n",
    "这些组件各自发挥着重要的作用：\n",
    "\n",
    "1. **智能体**：在上面单独定义的基础上，在多智能体系统中的智能体协同工作，每个智能体都具备独特有的LLM、观察、思考、行动和记忆。\n",
    "2. **环境**：环境是智能体生存和互动的公共场所。智能体从环境中观察到重要信息，并发布行动的输出结果以供其他智能体使用。\n",
    "3. **标准流程（SOP）**：这些是管理智能体行动和交互的既定程序，确保系统内部的有序和高效运作。例如，在汽车制造的SOP中，一个智能体焊接汽车零件，而另一个安装电缆，保持装配线的有序运作。\n",
    "4. **通信**：通信是智能体之间信息交流的过程。它对于系统内的协作、谈判和竞争至关重要。\n",
    "5. **经济**：这指的是多智能体环境中的价值交换系统，决定资源分配和任务优先级。\n",
    "\n",
    "## **任务**\n",
    "\n",
    "对于每一个任务，至少要明确两点：目标和期望。目标和期望都可以用自然语言去描述。\n",
    "\n",
    "其他需要明确的是上下文、回调、输出、使用的工具。\n",
    "\n",
    "回调可以是一个python函数。使用的工具可以是一个python列表。\n",
    "\n",
    "你可以用pydantic去约束输出的格式，把大模型的模糊输出变为强制结构化输出。\n",
    "\n",
    "## **工具**\n",
    "\n",
    "一个常用的工具就是搜索引擎。例如谷歌的 [serper](https://serper.dev/)。国内的替代品是什么？\n",
    "\n",
    "还有爬虫工具\n",
    "\n",
    "## **实践操作**"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "id": "2b69c11d",
   "metadata": {},
   "outputs": [
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "2025-02-26 13:27:04.273 | INFO     | metagpt.const:get_metagpt_package_root:29 - Package root set to /tmp/code/wow-agent/notebooks\n"
     ]
    }
   ],
   "source": [
    "import asyncio\n",
    "from metagpt.roles import (\n",
    "    Architect,\n",
    "    Engineer,\n",
    "    ProductManager,\n",
    "    ProjectManager,\n",
    ")\n",
    "from metagpt.team import Team\n",
    "async def startup(idea: str):\n",
    "    company = Team()\n",
    "    company.hire(\n",
    "        [\n",
    "            ProductManager(),\n",
    "            Architect(),\n",
    "            ProjectManager(),\n",
    "            Engineer(),\n",
    "        ]\n",
    "    )\n",
    "    company.invest(investment=3.0)\n",
    "    company.run_project(idea=idea)\n",
    "\n",
    "    await company.run(n_round=5)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "a14dcdf6",
   "metadata": {},
   "source": [
    "在上面的代码中，我们直接用默认的角色即可。这些角色都要做什么动作都已经写好了，直接拿过来用。\n",
    "\n",
    "然后执行下面这行代码，开始干活："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "id": "1d5a0f31",
   "metadata": {
    "scrolled": true
   },
   "outputs": [
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "2025-02-26 13:27:34.014 | INFO     | metagpt.team:invest:90 - Investment: $3.0.\n",
      "2025-02-26 13:27:34.019 | INFO     | metagpt.roles.role:_act:391 - Alice(Product Manager): to do PrepareDocuments(PrepareDocuments)\n",
      "2025-02-26 13:27:34.242 | INFO     | metagpt.utils.file_repository:save:57 - save to: /tmp/code/wow-agent/notebooks/workspace/20250226132734/docs/requirement.txt\n",
      "2025-02-26 13:27:34.251 | INFO     | metagpt.roles.role:_act:391 - Alice(Product Manager): to do WritePRD(WritePRD)\n",
      "2025-02-26 13:27:34.259 | INFO     | metagpt.actions.write_prd:run:86 - New requirement detected: 开发一个刷题程序\n"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[CONTENT]\n",
      "{\n",
      "    \"Language\": \"zh_cn\",\n",
      "    \"Programming Language\": \"Python\",\n",
      "    \"Original Requirements\": \"开发一个刷题程序\",\n",
      "    \"Project Name\": \"brush_questions_program\",\n",
      "    \"Product Goals\": [\n",
      "        \"打造一个吸引人的用户体验\",\n",
      "        \"提升易用性，确保响应性\",\n",
      "        \"设计更美观的用户界面\"\n",
      "    ],\n",
      "    \"User Stories\": [\n",
      "        \"作为一个用户，我希望能够选择不同的题目难度\",\n",
      "        \"作为一个用户，我希望在每完成一题后看到我的得分\",\n",
      "        \"作为一个用户，我希望在游戏失败时有一个重新开始按钮\",\n",
      "        \"作为一个用户，我希望看到美观的界面，让我有良好的使用体验\",\n",
      "        \"作为一个用户，我希望能够在手机上玩这个刷题程序\"\n",
      "    ],\n",
      "    \"Competitive Analysis\": [\n",
      "        \"刷题程序A：界面简单，缺乏响应性功能\",\n",
      "        \"刷题平台B：美观且响应性强的界面，显示最佳得分\",\n",
      "        \"刷题网站C：响应性强，显示最佳得分，但广告较多\"\n",
      "    ],\n",
      "    \"Competitive Quadrant Chart\": \"quadrantChart\\n    title \\\"活动的覆盖范围和参与度\\\"\\n    x-axis \\\"低覆盖范围\\\" --> \\\"高覆盖范围\\\"\\n    y-axis \\\"低参与度\\\" --> \\\"高参与度\\\"\\n    quadrant-1 \\\"我们应该扩展\\\"\\n    quadrant-2 \\\"需要推广\\\"\\n    quadrant-3 \\\"重新评估\\\"\\n    quadrant-4 \\\"可能改进\\\"\\n    \\\"活动A\\\": [0.3, 0.6]\\n    \\\"活动B\\\": [0.45, 0.23]\\n    \\\"活动C\\\": [0.57, 0.69]\\n    \\\"活动D\\\": [0.78, 0.34]\\n    \\\"活动E\\\": [0.40, 0.34]\\n    \\\"活动F\\\": [0.35, 0.78]\\n    \\\"我们的目标产品\\\": [0.5, 0.6]\",\n",
      "    \"Requirement Analysis\": \"\",\n",
      "    \"Requirement Pool\": [\n",
      "        [\n",
      "            \"P0\",\n",
      "            \"主程序代码...\"\n",
      "        ],\n",
      "        [\n",
      "            \"P0\",\n",
      "            \"题目算法...\"\n",
      "        ]\n",
      "    ],\n",
      "    \"UI Design draft\": \"基本功能描述，采用简单风格和布局。\",\n",
      "    \"Anything UNCLEAR\": \"\"\n",
      "}\n",
      "[/CONTENT]"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "2025-02-26 13:27:57.172 | WARNING  | metagpt.utils.cost_manager:update_cost:49 - Model glm-4-flash not found in TOKEN_COSTS.\n",
      "2025-02-26 13:27:57.194 | INFO     | metagpt.utils.git_repository:rename_root:219 - Rename directory /tmp/code/wow-agent/notebooks/workspace/20250226132734 to /tmp/code/wow-agent/notebooks/workspace/brush_questions_program\n",
      "2025-02-26 13:27:57.211 | INFO     | metagpt.utils.file_repository:save:57 - save to: /tmp/code/wow-agent/notebooks/workspace/brush_questions_program/docs/prd/20250226132757.json\n",
      "no mermaid\n",
      "2025-02-26 13:27:57.223 | WARNING  | metagpt.utils.mermaid:mermaid_to_file:35 - RUN `npm install -g @mermaid-js/mermaid-cli` to install mmdc,or consider changing engine to `playwright`, `pyppeteer`, or `ink`.\n",
      "2025-02-26 13:27:57.232 | INFO     | metagpt.utils.file_repository:save:57 - save to: /tmp/code/wow-agent/notebooks/workspace/brush_questions_program/resources/prd/20250226132757.md\n",
      "2025-02-26 13:27:57.242 | INFO     | metagpt.roles.role:_act:391 - Bob(Architect): to do WriteDesign(WriteDesign)\n"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\n",
      "[CONTENT]\n",
      "{\n",
      "    \"Implementation approach\": \"为了满足用户的需求，我们将采用Python作为开发语言，并利用以下开源库：Tkinter用于创建用户界面，SQLite作为轻量级数据库存储用户数据，以及Pillow库处理图片资源。我们将采用模块化设计，将程序分为几个主要模块：用户界面模块、题目管理模块、得分管理模块和数据库管理模块。\",\n",
      "    \"File list\": [\n",
      "        \"main.py\",\n",
      "        \"ui.py\",\n",
      "        \"questions.py\",\n",
      "        \"score.py\",\n",
      "        \"database.py\"\n",
      "    ],\n",
      "    \"Data structures and interfaces\": \"\\nclassDiagram\\n    class Main {\\n        -UI ui\\n        -Questions questions\\n        -Score score\\n        -Database database\\n        +start() void\\n    }\\n    class UI {\\n        +display_menu() void\\n        +display_question(question: str) void\\n        +display_score(score: int) void\\n        +display_game_over() void\\n    }\\n    class Questions {\\n        +get_questions(difficulty: str) list[str]\\n        +get_next_question() str\\n    }\\n    class Score {\\n        +get_score() int\\n        +update_score(score: int) void\\n    }\\n    class Database {\\n        +initialize() void\\n        +save_score(score: int) void\\n        +load_scores() list[int]\\n    }\\n    Main --> UI\\n    Main --> Questions\\n    Main --> Score\\n    Main --> Database\\n\",\n",
      "    \"Program call flow\": \"\\nsequenceDiagram\\n    participant M as Main\\n    participant U as UI\\n    participant Q as Questions\\n    participant S as Score\\n    participant D as Database\\n    M->>U: start()\\n    alt 显示菜单\\n        U->>M: display_menu()\\n    else 显示题目\\n        U->>Q: get_next_question()\\n        U->>M: display_question(Q.get_next_question())\\n        U->>S: get_score()\\n        U->>M: display_score(S.get_score())\\n    else 游戏结束\\n        U->>M: display_game_over()\\n    else 保存得分\\n        U->>D: save_score(S.get_score())\\n    else 加载得分\\n        U->>D: load_scores()\\n    else 更新得分\\n        U->>S: update_score(score)\\n    end\\n\",\n",
      "    \"Anything UNCLEAR\": \"目前没有发现项目中的不明确点，但需要确保题目库的丰富性和题目的难度分级能够满足不同用户的需求。"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "2025-02-26 13:28:30.115 | WARNING  | metagpt.utils.cost_manager:update_cost:49 - Model glm-4-flash not found in TOKEN_COSTS.\n",
      "2025-02-26 13:28:30.133 | INFO     | metagpt.utils.file_repository:save:57 - save to: /tmp/code/wow-agent/notebooks/workspace/brush_questions_program/docs/system_design/20250226132757.json\n",
      "2025-02-26 13:28:30.139 | INFO     | metagpt.utils.file_repository:save:62 - update dependency: /tmp/code/wow-agent/notebooks/workspace/brush_questions_program/docs/system_design/20250226132757.json:{'docs/prd/20250226132757.json'}\n",
      "no mermaid\n",
      "2025-02-26 13:28:30.148 | WARNING  | metagpt.utils.mermaid:mermaid_to_file:35 - RUN `npm install -g @mermaid-js/mermaid-cli` to install mmdc,or consider changing engine to `playwright`, `pyppeteer`, or `ink`.\n",
      "2025-02-26 13:28:30.149 | INFO     | metagpt.actions.design_api:_save_data_api_design:107 - Save class view to /tmp/code/wow-agent/notebooks/workspace/brush_questions_program/resources/data_api_design/20250226132757\n",
      "no mermaid\n",
      "2025-02-26 13:28:30.158 | WARNING  | metagpt.utils.mermaid:mermaid_to_file:35 - RUN `npm install -g @mermaid-js/mermaid-cli` to install mmdc,or consider changing engine to `playwright`, `pyppeteer`, or `ink`.\n",
      "2025-02-26 13:28:30.160 | INFO     | metagpt.actions.design_api:_save_seq_flow:116 - Saving sequence flow to /tmp/code/wow-agent/notebooks/workspace/brush_questions_program/resources/seq_flow/20250226132757\n",
      "2025-02-26 13:28:30.165 | INFO     | metagpt.utils.file_repository:save:57 - save to: /tmp/code/wow-agent/notebooks/workspace/brush_questions_program/resources/system_design/20250226132757.md\n",
      "2025-02-26 13:28:30.174 | INFO     | metagpt.roles.role:_act:391 - Eve(Project Manager): to do WriteTasks(WriteTasks)\n"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\"\n",
      "}\n",
      "[/CONTENT]\n",
      "[CONTENT]\n",
      "{\n",
      "    \"Required Python packages\": [\n",
      "        \"tkinter\",\n",
      "        \"sqlite3\",\n",
      "        \"Pillow\"\n",
      "    ],\n",
      "    \"Required Other language third-party packages\": [\n",
      "        \"No third-party dependencies required\"\n",
      "    ],\n",
      "    \"Logic Analysis\": [\n",
      "        [\n",
      "            \"ui.py\",\n",
      "            \"Contains UI class with methods display_menu(), display_question(), display_score(), and display_game_over()\"\n",
      "        ],\n",
      "        [\n",
      "            \"questions.py\",\n",
      "            \"Contains Questions class with methods get_questions(difficulty: str) and get_next_question()\"\n",
      "        ],\n",
      "        [\n",
      "            \"score.py\",\n",
      "            \"Contains Score class with methods get_score() and update_score(score: int)\"\n",
      "        ],\n",
      "        [\n",
      "            \"database.py\",\n",
      "            \"Contains Database class with methods initialize(), save_score(score: int), load_scores(), and get_scores()\"\n",
      "        ],\n",
      "        [\n",
      "            \"main.py\",\n",
      "            \"Contains Main class with start() method and dependencies to UI, Questions, Score, and Database\"\n",
      "        ]\n",
      "    ],\n",
      "    \"Task list\": [\n",
      "        \"ui.py\",\n",
      "        \"questions.py\",\n",
      "        \"score.py\",\n",
      "        \"database.py\",\n",
      "        \"main.py\"\n",
      "    ],\n",
      "    \"Full API spec\": \"No API spec required as the application is a command-line interface and does not require external communication.\",\n",
      "    \"Shared Knowledge\": \"The application uses a SQLite database for storing user data and a Pillow library for image processing. The Tkinter library is used for the GUI.\",\n",
      "    \"Anything UNCLEAR\": \"Ensure that the difficulty levels of the questions are well-defined and that the database schema supports the required operations"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "2025-02-26 13:28:44.359 | WARNING  | metagpt.utils.cost_manager:update_cost:49 - Model glm-4-flash not found in TOKEN_COSTS.\n",
      "2025-02-26 13:28:44.370 | INFO     | metagpt.utils.file_repository:save:57 - save to: /tmp/code/wow-agent/notebooks/workspace/brush_questions_program/docs/task/20250226132757.json\n",
      "2025-02-26 13:28:44.377 | INFO     | metagpt.utils.file_repository:save:62 - update dependency: /tmp/code/wow-agent/notebooks/workspace/brush_questions_program/docs/task/20250226132757.json:{'docs/system_design/20250226132757.json'}\n",
      "2025-02-26 13:28:44.382 | INFO     | metagpt.utils.file_repository:save:57 - save to: /tmp/code/wow-agent/notebooks/workspace/brush_questions_program/requirements.txt\n"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      ".\"\n",
      "}\n",
      "[/CONTENT]\n"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "2025-02-26 13:28:44.743 | INFO     | metagpt.actions.write_code:run:141 - Writing ui.py..\n"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "## Code: ui.py\n",
      "```python\n",
      "import tkinter as tk\n",
      "from PIL import Image, ImageTk\n",
      "\n",
      "class UI:\n",
      "    def __init__(self, root):\n",
      "        self.root = root\n",
      "        self.root.title(\"Quiz Game\")\n",
      "        self.root.geometry(\"800x600\")\n",
      "        self.menu_screen()\n",
      "    \n",
      "    def menu_screen(self):\n",
      "        self.root.title(\"Main Menu\")\n",
      "        menu_frame = tk.Frame(self.root)\n",
      "        menu_frame.pack(pady=20)\n",
      "        \n",
      "        start_button = tk.Button(menu_frame, text=\"Start Quiz\", command=self.start_quiz)\n",
      "        start_button.pack(pady=10)\n",
      "        \n",
      "        exit_button = tk.Button(menu_frame, text=\"Exit\", command=self.root.quit)\n",
      "        exit_button.pack(pady=10)\n",
      "    \n",
      "    def start_quiz(self):\n",
      "        self.root.title(\"Quiz\")\n",
      "        self.question_frame = tk.Frame(self.root)\n",
      "        self.question_frame.pack(pady=20)\n",
      "        \n",
      "        self.question_label = tk.Label(self.question_frame, text=\"\", font=(\"Arial\", 18))\n",
      "        self.question_label.pack(pady=10)\n",
      "        \n",
      "        self.score_label = tk.Label(self.question_frame, text=\"Score: 0\", font=(\"Arial\", 18))\n",
      "        self.score_label.pack(pady=10)\n",
      "        \n",
      "        self.next_button = tk.Button(self.question_frame, text=\"Next\", command=self.next_question)\n",
      "        self.next_button.pack(pady=10)\n",
      "        \n",
      "        self.game_over_screen()\n",
      "    \n",
      "    def display_question(self, question):\n",
      "        self.question_label.config(text=question)\n",
      "    \n",
      "    def display_score(self, score):\n",
      "        self.score_label.config(text=f\"Score: {score}\")\n",
      "    \n",
      "    def display_game_over(self, score):\n",
      "        self.root.title(\"Game Over\")\n",
      "        self.question_frame.destroy()\n",
      "        \n",
      "        game_over_frame = tk.Frame(self.root)\n",
      "        game_over_frame.pack(pady=20)\n",
      "        \n",
      "        game_over_label = tk.Label(game_over_frame, text=f\"Game Over! Your score is {score}\", font=(\"Arial\", 18))\n",
      "        game_over_label.pack(pady=10)\n",
      "        \n",
      "        restart_button = tk.Button(game_over_frame, text=\"Restart\", command=self.restart_game)\n",
      "        restart_button.pack(pady=10)\n",
      "        \n",
      "        exit_button = tk.Button(game_over_frame, text=\"Exit\", command=self.root.quit)\n",
      "        exit_button.pack(pady=10)\n",
      "    \n",
      "    def game_over_screen(self):\n",
      "        pass\n",
      "    \n",
      "    def next_question(self):\n",
      "        pass\n",
      "    \n",
      "    def restart_game(self):\n",
      "        self.root.title(\"Quiz\")\n",
      "        self.question_frame.destroy()\n",
      "        self.menu_screen()\n",
      "```"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "2025-02-26 13:29:03.091 | WARNING  | metagpt.utils.cost_manager:update_cost:49 - Model glm-4-flash not found in TOKEN_COSTS.\n",
      "2025-02-26 13:29:03.115 | INFO     | metagpt.utils.file_repository:save:57 - save to: /tmp/code/wow-agent/notebooks/workspace/brush_questions_program/brush_questions_program/ui.py\n",
      "2025-02-26 13:29:03.125 | INFO     | metagpt.utils.file_repository:save:62 - update dependency: /tmp/code/wow-agent/notebooks/workspace/brush_questions_program/brush_questions_program/ui.py:['docs/system_design/20250226132757.json', 'docs/task/20250226132757.json']\n",
      "2025-02-26 13:29:03.135 | INFO     | metagpt.actions.write_code:run:141 - Writing questions.py..\n"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\n",
      "## Code: questions.py\n",
      "```python\n",
      "class Questions:\n",
      "    def __init__(self, question_data):\n",
      "        self.question_data = question_data\n",
      "        self.difficulty_levels = {\"easy\": [], \"medium\": [], \"hard\": []}\n",
      "        self.initialize_questions()\n",
      "\n",
      "    def initialize_questions(self):\n",
      "        for difficulty, questions in self.question_data.items():\n",
      "            for question in questions:\n",
      "                self.difficulty_levels[difficulty].append(question)\n",
      "\n",
      "    def get_questions(self, difficulty: str):\n",
      "        if difficulty not in self.difficulty_levels:\n",
      "            raise ValueError(\"Invalid difficulty level\")\n",
      "        return self.difficulty_levels[difficulty]\n",
      "\n",
      "    def get_next_question(self):\n",
      "        if not self.question_data:\n",
      "            raise Exception(\"No more questions available\")\n",
      "        difficulty = self.get_random_difficulty()\n",
      "        question = self.get_random_question_from_difficulty(difficulty)\n",
      "        self.remove_question_from_difficulty(difficulty, question)\n",
      "        return question\n",
      "\n",
      "    def get_random_difficulty(self):\n",
      "        return random.choice(list(self.difficulty_levels.keys()))\n",
      "\n",
      "    def get_random_question_from_difficulty(self, difficulty):\n",
      "        return random.choice(self.difficulty_levels[difficulty])\n",
      "\n",
      "    def remove_question_from_difficulty(self, difficulty, question):\n",
      "        self.difficulty_levels[difficulty].remove(question)\n",
      "        if not self.difficulty_levels[difficulty]:\n",
      "            del self.difficulty_levels[difficulty]\n",
      "```\n",
      "\n",
      "This code defines a `Questions` class that manages a set of questions with different difficulty levels. The `initialize_questions` method populates the `difficulty_levels` dictionary with questions categorized by their difficulty. The `get_questions` method returns a list of questions for a specified difficulty level. The `get_next_question` method retrieves the next question from the pool, ensuring that each question is only used once. The `get_random_difficulty` and `get_random_question_from_difficulty` methods are helper functions to select a random difficulty level and question from that level, respectively. The `remove_question_from_difficulty` method removes a question from the pool after it has been used."
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "2025-02-26 13:29:25.066 | WARNING  | metagpt.utils.cost_manager:update_cost:49 - Model glm-4-flash not found in TOKEN_COSTS.\n",
      "2025-02-26 13:29:25.090 | INFO     | metagpt.utils.file_repository:save:57 - save to: /tmp/code/wow-agent/notebooks/workspace/brush_questions_program/brush_questions_program/questions.py\n",
      "2025-02-26 13:29:25.100 | INFO     | metagpt.utils.file_repository:save:62 - update dependency: /tmp/code/wow-agent/notebooks/workspace/brush_questions_program/brush_questions_program/questions.py:['docs/system_design/20250226132757.json', 'docs/task/20250226132757.json']\n",
      "2025-02-26 13:29:25.113 | INFO     | metagpt.actions.write_code:run:141 - Writing score.py..\n"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\n",
      "## Code: score.py\n",
      "```python\n",
      "class Score:\n",
      "    def __init__(self, initial_score=0):\n",
      "        self._score = initial_score\n",
      "\n",
      "    def get_score(self) -> int:\n",
      "        return self._score\n",
      "\n",
      "    def update_score(self, score_change: int) -> None:\n",
      "        if not isinstance(score_change, int):\n",
      "            raise ValueError(\"Score change must be an integer\")\n",
      "        self._score += score_change\n",
      "```"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "2025-02-26 13:29:30.896 | WARNING  | metagpt.utils.cost_manager:update_cost:49 - Model glm-4-flash not found in TOKEN_COSTS.\n",
      "2025-02-26 13:29:30.919 | INFO     | metagpt.utils.file_repository:save:57 - save to: /tmp/code/wow-agent/notebooks/workspace/brush_questions_program/brush_questions_program/score.py\n",
      "2025-02-26 13:29:30.929 | INFO     | metagpt.utils.file_repository:save:62 - update dependency: /tmp/code/wow-agent/notebooks/workspace/brush_questions_program/brush_questions_program/score.py:['docs/system_design/20250226132757.json', 'docs/task/20250226132757.json']\n",
      "2025-02-26 13:29:30.941 | INFO     | metagpt.actions.write_code:run:141 - Writing database.py..\n"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\n",
      "## Code: database.py\n",
      "```python\n",
      "import sqlite3\n",
      "\n",
      "class Database:\n",
      "    def __init__(self, db_path='quiz_game.db', init_schema=False):\n",
      "        self.db_path = db_path\n",
      "        self.conn = None\n",
      "        self.initialize_db(init_schema)\n",
      "\n",
      "    def initialize_db(self, init_schema):\n",
      "        self.conn = sqlite3.connect(self.db_path)\n",
      "        cursor = self.conn.cursor()\n",
      "        if init_schema:\n",
      "            cursor.execute('''\n",
      "                CREATE TABLE IF NOT EXISTS scores (\n",
      "                    id INTEGER PRIMARY KEY AUTOINCREMENT,\n",
      "                    score INTEGER NOT NULL\n",
      "                )\n",
      "            ''')\n",
      "            self.conn.commit()\n",
      "\n",
      "    def save_score(self, score: int) -> None:\n",
      "        cursor = self.conn.cursor()\n",
      "        cursor.execute('INSERT INTO scores (score) VALUES (?)', (score,))\n",
      "        self.conn.commit()\n",
      "\n",
      "    def load_scores(self) -> list[int]:\n",
      "        cursor = self.conn.cursor()\n",
      "        cursor.execute('SELECT score FROM scores')\n",
      "        return [row[0] for row in cursor.fetchall()]\n",
      "\n",
      "    def get_scores(self) -> list[int]:\n",
      "        return self.load_scores()\n",
      "\n",
      "    def close(self) -> None:\n",
      "        if self.conn:\n",
      "            self.conn.close()\n",
      "```"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "2025-02-26 13:29:41.495 | WARNING  | metagpt.utils.cost_manager:update_cost:49 - Model glm-4-flash not found in TOKEN_COSTS.\n",
      "2025-02-26 13:29:41.518 | INFO     | metagpt.utils.file_repository:save:57 - save to: /tmp/code/wow-agent/notebooks/workspace/brush_questions_program/brush_questions_program/database.py\n",
      "2025-02-26 13:29:41.528 | INFO     | metagpt.utils.file_repository:save:62 - update dependency: /tmp/code/wow-agent/notebooks/workspace/brush_questions_program/brush_questions_program/database.py:['docs/system_design/20250226132757.json', 'docs/task/20250226132757.json']\n",
      "2025-02-26 13:29:41.543 | INFO     | metagpt.actions.write_code:run:141 - Writing main.py..\n"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\n",
      "## Code: main.py\n",
      "```python\n",
      "import tkinter as tk\n",
      "from PIL import Image, ImageTk\n",
      "import sqlite3\n",
      "import random\n",
      "\n",
      "# Importing the classes from other modules\n",
      "from ui import UI\n",
      "from questions import Questions\n",
      "from score import Score\n",
      "from database import Database\n",
      "\n",
      "class Main:\n",
      "    def __init__(self, root):\n",
      "        self.root = root\n",
      "        self.ui = UI(self.root)\n",
      "        self.questions = Questions(question_data=self.load_questions())\n",
      "        self.score = Score()\n",
      "        self.database = Database()\n",
      "        self.ui.start()\n",
      "\n",
      "    def load_questions(self):\n",
      "        # Placeholder for question data loading logic\n",
      "        # This should be replaced with actual data loading logic\n",
      "        return {\n",
      "            \"easy\": [\"What is 2 + 2?\", \"What is the capital of France?\"],\n",
      "            \"medium\": [\"What is the square root of 16?\", \"What is the capital of Germany?\"],\n",
      "            \"hard\": [\"What is the chemical symbol for gold?\", \"What is the capital of Italy?\"]\n",
      "        }\n",
      "\n",
      "    def start(self):\n",
      "        self.ui.display_menu()\n",
      "\n",
      "    def display_menu(self):\n",
      "        self.ui.display_menu()\n",
      "\n",
      "    def display_question(self, question):\n",
      "        self.ui.display_question(question)\n",
      "        self.score.update_score(1)  # Assuming each question is worth 1 point\n",
      "        self.ui.display_score(self.score.get_score())\n",
      "\n",
      "    def display_score(self, score):\n",
      "        self.ui.display_score(score)\n",
      "\n",
      "    def display_game_over(self, score):\n",
      "        self.ui.display_game_over(score)\n",
      "        self.database.save_score(score)\n",
      "\n",
      "    def next_question(self):\n",
      "        try:\n",
      "            next_question = self.questions.get_next_question()\n",
      "            self.display_question(next_question)\n",
      "        except Exception as e:\n",
      "            self.display_game_over(self.score.get_score())\n",
      "\n",
      "    def restart_game(self):\n",
      "        self.score = Score()\n",
      "        self.questions = Questions(question_data=self.load_questions())\n",
      "        self.ui.restart_game()\n",
      "\n",
      "    def run(self):\n",
      "        self.root.mainloop()\n",
      "\n",
      "if __name__ == \"__main__\":\n",
      "    root = tk.Tk()\n",
      "    main_app = Main(root)\n",
      "    main_app"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "2025-02-26 13:30:04.519 | WARNING  | metagpt.utils.cost_manager:update_cost:49 - Model glm-4-flash not found in TOKEN_COSTS.\n"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      ".run()\n",
      "```\n"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "2025-02-26 13:30:04.543 | INFO     | metagpt.utils.file_repository:save:57 - save to: /tmp/code/wow-agent/notebooks/workspace/brush_questions_program/brush_questions_program/main.py\n",
      "2025-02-26 13:30:04.552 | INFO     | metagpt.utils.file_repository:save:62 - update dependency: /tmp/code/wow-agent/notebooks/workspace/brush_questions_program/brush_questions_program/main.py:['docs/system_design/20250226132757.json', 'docs/task/20250226132757.json']\n",
      "2025-02-26 13:30:04.600 | INFO     | metagpt.utils.git_repository:archive:168 - Archive: ['.dependencies.json', 'brush_questions_program/database.py', 'brush_questions_program/main.py', 'brush_questions_program/questions.py', 'brush_questions_program/score.py', 'brush_questions_program/ui.py', 'docs/prd/20250226132757.json', 'docs/requirement.txt', 'docs/system_design/20250226132757.json', 'docs/task/20250226132757.json', 'requirements.txt', 'resources/competitive_analysis/20250226132757.mmd', 'resources/data_api_design/20250226132757.mmd', 'resources/prd/20250226132757.md', 'resources/seq_flow/20250226132757.mmd', 'resources/system_design/20250226132757.md']\n"
     ]
    }
   ],
   "source": [
    "await startup(idea=\"开发一个刷题程序\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "50f1d5e9",
   "metadata": {},
   "outputs": [],
   "source": []
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3 (ipykernel)",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.10.11"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 5
}
